/*
 * BlackLightning.PluginLib.Components.SalFile
 * Andy Tidball
 * 
 * Project: Black Lightning Plugin Library
 * Copyright: GNU General Public License
 */

using System;
using System.IO;
using System.Net;

namespace BlackLightning.PluginLib.LoginClients {
	/// <summary>
	/// Abstraction of a Simutronics Auto-Launch (SAL) file.
	/// </summary>
	[Serializable]
	public class SalFile {
		/// <summary>
		/// Loads an SAL file from the given Filename.
		/// </summary>
		/// <param name="Filename">The name of the SAL file, also assumed to be the name of the character being played.</param>
		/// <returns>An instance of SalFile which represents the file with the given filename.</returns>
		public static SalFile Load(string Filename) {
			// create info about the given filename
			FileInfo Info = new FileInfo(Filename);

			// open the file for reading
			StreamReader In = new StreamReader(Info.OpenRead());

			// read the entire contents
			string Contents = In.ReadToEnd();

			// close the file
			In.Close();

			// create a new instance given the file's name and contents
			return new SalFile(Info.Name.Replace(Info.Extension,""), Contents);
		}

		// member data
		private int    _UpdatePort     = 0;    // the port to check for updates at
		private string _ClientCode     = null; // the code identifying the client program to use
		private string _ClientName     = null; // the name of the client program to use
		private string _ClientFilename = null; // the filename of the client program to use
		private string _GameCode       = null; // the code identifying the game to connect to
		private string _GameHost       = null; // the URL to connect to the game at
		private int    _GamePort       = 0;    // the port to connect to the game on
		private string _Key            = null; // the key to use to login to the game
		private string _Character      = null; // the character being played

		/// <summary>
		/// Creates a new SalFile.
		/// </summary>
		/// <param name="Character">The name of the character being played.</param>
		/// <param name="Contents">The contents of the SAL file to parse.</param>
		public SalFile(string Character, string Contents) {
			// save the character name
			_Character = Character;

			// split the contents into lines and loop over each
			Contents = Contents.Replace("\r\n", "\n");
			string[] Split = Contents.Split('\n');
			foreach (string Line in Split) {
				// skip the line if it's empty
				if (Line == string.Empty) {
					continue;
				}

				// split the line into a name and a value
				string[] Pair  = Line.Split('=');
				string   Name  = Pair[0];
				string   Value = Pair[1];

				// store the appropriate property
				switch (Name) {
					case "UPPORT":       _UpdatePort     = int.Parse(Value); break;
					case "GAME":         _ClientCode     = Value;            break;
					case "FULLGAMENAME": _ClientName     = Value;            break;
					case "GAMEFILE":     _ClientFilename = Value;            break;
					case "GAMECODE":     _GameCode       = Value;            break;
					case "GAMEHOST":     _GameHost       = Value;            break;
					case "GAMEPORT":     _GamePort       = int.Parse(Value); break;
					case "KEY":          _Key            = Value;            break;
				}
			}
		}

		/// <summary>
		/// Copy constructor.
		/// </summary>
		/// <param name="Source">The SalFile to copy when creating the new one.</param>
		public SalFile(SalFile Source) {
			_UpdatePort     = Source._UpdatePort;
			_ClientCode     = Source._ClientCode;
			_ClientName     = Source._ClientName;
			_ClientFilename = Source._ClientFilename;
			_GameCode       = Source._GameCode;
			_GameHost       = Source._GameHost;
			_GamePort       = Source._GamePort;
			_Key            = Source._Key;
			_Character      = Source._Character;
		}

		/// <summary>
		/// Gets or sets the port to check for updates.
		/// </summary>
		public int UpdatePort {
			get {
				return _UpdatePort;
			}
			set {
				_UpdatePort = value;
			}
		}

		/// <summary>
		/// Gets or sets the code identifying the client program to use.
		/// </summary>
		public string ClientCode {
			get {
				return _ClientCode;
			}
			set {
				_ClientCode = value;
			}
		}

		/// <summary>
		/// Gets or sets the client program to use.
		/// </summary>
		public FrontEnd FrontEnd {
			get {
				switch (_ClientCode) {
					case "STORM": return FrontEnd.StormFront;
					case "PLAY":  return FrontEnd.Wizard;
					case "WIZ":   return FrontEnd.Wizard;
					default:      throw new ArgumentOutOfRangeException("Unrecognized front end code: " + _ClientCode);
				}
			}
			set {
				switch (value) {
					case FrontEnd.StormFront: _ClientCode = "STORM"; break;
					case FrontEnd.Wizard:     _ClientCode = "WIZ";   break;
					default:                  throw new ArgumentOutOfRangeException("Unrecognized front end: " + value.ToString());
				}
			}
		}

		/// <summary>
		/// Gets or sets the name of the client program to use.
		/// </summary>
		public string ClientName {
			get {
				return _ClientName;
			}
			set {
				_ClientName = value;
			}
		}

		/// <summary>
		/// Gets or sets the filename of the client program to use.
		/// </summary>
		public string ClientFilename {
			get {
				return _ClientFilename;
			}
			set {
				_ClientFilename = value;
			}
		}

		/// <summary>
		/// Gets or sets the code identifying the game to connect to.
		/// </summary>
		public string GameCode {
			get {
				return _GameCode;
			}
			set {
				_GameCode = value;
			}
		}

		/// <summary>
		/// Gets or sets the game to connect to.
		/// </summary>
		public Game Game {
			get {
				switch (_GameCode) {
					case "DR":   return Game.DragonRealms;
					case "DRF":  return Game.DragonRealmsFallen;
					case "DRX":  return Game.DragonRealmsPlatinum;
					case "DRDT": return Game.DragonRealmsDevelopment;
					case "GS":   return Game.GemStone;
					case "GS3":  return Game.GemStone;
					case "GSX":  return Game.GemStonePlatinum;
					case "GS4D": return Game.GemStoneDevelopment;
					case "HX":   return Game.AllianceOfHeroes;
					case "HXD":  return Game.AllianceOfHeroesDevelopment;
					case "MO":   return Game.ModusOperandi;
					case "MOD":  return Game.ModusOperandiDevelopment;
					default:     throw new ArgumentOutOfRangeException("Unrecognized game code: " + _GameCode);
				}
			}
			set {
				switch (value) {
					case Game.AllianceOfHeroes:            _GameCode = "HX";   break;
					case Game.AllianceOfHeroesDevelopment: _GameCode = "HXD";  break;
					case Game.DragonRealms:                _GameCode = "DR";   break;
					case Game.DragonRealmsDevelopment:     _GameCode = "DRDT"; break;
					case Game.DragonRealmsFallen:          _GameCode = "DRF";  break;
					case Game.DragonRealmsPlatinum:        _GameCode = "DRX";  break;
					case Game.GemStone:                    _GameCode = "GS";   break;
					case Game.GemStoneDevelopment:         _GameCode = "GS4D"; break;
					case Game.GemStonePlatinum:            _GameCode = "GSX";  break;
					case Game.ModusOperandi:               _GameCode = "MO";   break;
					case Game.ModusOperandiDevelopment:    _GameCode = "MOD";  break;
					default:                               throw new ArgumentOutOfRangeException("Unrecognized game: " + value.ToString());
				}
			}
		}

		/// <summary>
		/// Gets or sets the URL to connect to the game at.
		/// </summary>
		public string GameHost {
			get {
				return _GameHost;
			}
			set {
				_GameHost = value;
			}
		}

		/// <summary>
		/// Gets or sets the port to connect to the game on.
		/// </summary>
		public int GamePort {
			get {
				return _GamePort;
			}
			set {
				_GamePort = value;
			}
		}

		/// <summary>
		/// Gets or sets the key to use to login to the game with.
		/// </summary>
		public string Key {
			get {
				return _Key;
			}
			set {
				_Key = value;
			}
		}

		/// <summary>
		/// Gets or sets the name of the character that is to be played.
		/// </summary>
		public string Character {
			get {
				return _Character;
			}
			set {
				_Character = value;
			}
		}

		/// <summary>
		/// Creates an IPEndPoint representing GameHost and GamePort.
		/// </summary>
		/// <returns>An IPEndPoint representing GameHost and GamePort.</returns>
		public IPEndPoint CreateGameEndPoint() {
			return new IPEndPoint(Dns.GetHostEntry(GameHost).AddressList[0], GamePort);
		}

		/// <summary>
		/// Saves the SAL file in the given directory using Character as the filename.
		/// </summary>
		/// <param name="Directory">The directory to save the SAL file to.</param>
		/// <returns>The full path and filename of the saved SAL file.</returns>
		public string Save(string Directory) {
			// construct the full filename for the file
			if (!Directory.EndsWith(Path.DirectorySeparatorChar.ToString())) {
				Directory += Path.DirectorySeparatorChar;
			}
			string FullFilename = Directory + Character + ".sal";

			// create a FileInfo out of the name and open it for writing
			FileInfo Info = new FileInfo(FullFilename);
			StreamWriter Out = new StreamWriter(Info.OpenWrite());

			// write out the information
			Out.WriteLine("UPPORT="       + UpdatePort);
			Out.WriteLine("GAME="         + ClientCode);
			Out.WriteLine("GAMECODE="     + _GameCode);
			Out.WriteLine("FULLGAMENAME=" + _ClientName);
			Out.WriteLine("GAMEFILE="     + _ClientFilename);
			Out.WriteLine("GAMEHOST="     + _GameHost);
			Out.WriteLine("GAMEPORT="     + _GamePort);
			Out.WriteLine("KEY="          + _Key);

			// close the file
			Out.Close();

			// return the full filename
			return FullFilename;
		}
	}
}
